{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wJcYs_ERTnnI"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "HMUDt0CiUJk9"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "77z2OchJTk0l"
      },
      "source": [
        "# Конвертируйте ваш существующий код в TensorFlow 2.0\n",
        "\n",
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/guide/migrate\">\n",
        "    <img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />\n",
        "    Смотрите на TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ru/guide/migrate.ipynb\">\n",
        "    <img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />\n",
        "    Запустите в Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ru/guide/migrate.ipynb\">\n",
        "    <img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />\n",
        "    Изучайте код на GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs/site/ru/guide/migrate.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Скачайте ноутбук</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fj66ZXAzrJC2",
        "colab_type": "text"
      },
      "source": [
        "Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует [официальной документации на английском языке](https://www.tensorflow.org/?hl=en). Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в [tensorflow/docs](https://github.com/tensorflow/docs) репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на [docs-ru@tensorflow.org list](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ru)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "C0V10enS1_WU"
      },
      "source": [
        "В TensorFlow 2.0 все еще возможно исполнить 1.X код без изменений (за исключением contrib):\n",
        "\n",
        "```\n",
        "import tensorflow.compat.v1 as tf\n",
        "tf.disable_v2_behavior()\n",
        "```\n",
        "\n",
        "Однако, это не дает вам воспользоваться преимуществами многих улучшений сделанных в TensorFlow 2.0. Это руководство поможет вам обновить ваш код, сделав его проще, производительнее и легче в поддержке.\n",
        "\n",
        "## Скрипт автоматической конвертации\n",
        "\n",
        "Первым шагом вы можете попробовать запустить [скрипт обновления](./upgrade.md).\n",
        "\n",
        "Он выполнит начальный этап обновления вашего кода до TensorFlow 2.0. Но это не может сделать ваш код идиоматичным TensorFlowF 2.0. Ваш код все еще может использовать `tf.compat.v1` для доступа к плейсхолдерам, сессиям, коллекциям, и другой функциональности в стиле 1.x.\n",
        "\n",
        "## Сделайте код 2.0-нативным\n",
        "\n",
        "\n",
        "В этом руководстве рассматриваются несколько примеров преобразования кода TensorFlow 1.x в TensorFlow 2.0. Эти изменения позволят вашему коду воспользоваться преимуществами оптимизации производительности и упрощенных вызовов API.\n",
        "\n",
        "В каждом случае паттерн следующий:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "uP0O8Pc45LNs"
      },
      "source": [
        "### 1. Заменить вызовы `tf.Session.run`\n",
        "\n",
        "Каждый вызов `tf.Session.run` нужо заменить функцией Python.\n",
        "\n",
        "* `feed_dict` и `tf.placeholder`s становятся аргументами функции.\n",
        "*  `fetches` становится возвращаемым значением функции.\n",
        "\n",
        "Вы можете пройти пошагово и отладить функцию, используя стандартные инструменты Python, такие как `pdb`.\n",
        "\n",
        "Когда вы убедитесь, что функция работает, добавьте декоратор`tf.function` чтобы она работала эффективно в режиме графа. Смотри [Руководство Autograph](function.ipynb) чтобы узнать больше о том, как это работает."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "jlBOqROL5NmN"
      },
      "source": [
        "### 2. Используйте объекты python для отслеживания переменных и значений потерь\n",
        "\n",
        "Используйте `tf.Variable` вместо `tf.get_variable`.\n",
        "\n",
        "Каждый `variable_scope` может быть сконвертирован в объект Python. Как правило это будет что-то из:\n",
        "\n",
        "* `tf.keras.layers.Layer`\n",
        "* `tf.keras.Model`\n",
        "* `tf.Module`\n",
        "\n",
        "Если вам нужны свести списки переменных (как например `tf.Graph.get_collection(tf.GraphKeys.VARIABLES)`), используйте аттрибуты `.variables` и `.trainable_variables` объектов `Layer` и `Model`.\n",
        "\n",
        "Эти классы `Layer` и `Model` реализуют несколько других свойств которые устраняют необходимость глобальных коллекций.\n",
        "\n",
        "Смотри [руководства keras](keras.ipynb) для подробностей.\n",
        "\n",
        "Предупреждение: Многие символы `tf.compat.v1` неявно используют глобальные коллекции.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rGFhBzoF5FIq"
      },
      "source": [
        "### 3. Обновите ваши обучающие циклы\n",
        "\n",
        "Используйте API наиболее высокого уровня который работает в вашем случае.  Предпочтите `tf.keras.Model.fit` построению своего собственного обучающего цикла.\n",
        "\n",
        "Эти высокоуровневые функции управляют большим количеством низкоуровневых деталей которые могут быть легко упущены если вы пишете собственный обучающий цикл. Например, они автоматически собирают потери регуляризации и устанавливают аргумент `training = True` при вызове модели.\n",
        "\n",
        "### 4. Обновите ваши конвейеры ввода данных\n",
        "\n",
        "Используйте наборы данных `tf.data` для входных данных. Эти объекты эффективны, выразительны и хорошо интегрированы с tensorflow.\n",
        "\n",
        "Их можно передать напрямую в метод `tf.keras.Model.fit`.\n",
        "\n",
        "```\n",
        "model.fit(dataset, epochs=5)\n",
        "```\n",
        "\n",
        "Их можно напрямую итерировать в стандартном Python:\n",
        "\n",
        "```\n",
        "for example_batch, label_batch in dataset:\n",
        "    break\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "X_ilfTGJ4Yml"
      },
      "source": [
        "## Конвертация моделей\n",
        "\n",
        "### Установка"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "bad2N-Z115W1"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "try:\n",
        "  # %tensorflow_version only exists in Colab.\n",
        "  import tensorflow.compat.v2 as tf\n",
        "except Exception:\n",
        "  pass\n",
        "tf.enable_v2_behavior()\n",
        "\n",
        "\n",
        "import tensorflow_datasets as tfds"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "FB99sqHX2Q5m"
      },
      "source": [
        "### Низкоуровневые переменные и исполнение оператора\n",
        "\n",
        "Примеры использования низкоуровневого API включают:\n",
        "\n",
        "* использование областей видимости переменных для управления повторным использованием\n",
        "* создание переменных с `tf.get_variable`.\n",
        "* явный доступ к коллекциям\n",
        "* неявный доступ к коллекциям с такими методами, как:\n",
        "\n",
        "  * `tf.global_variables`\n",
        "  * `tf.losses.get_regularization_loss`\n",
        "\n",
        "* использование `tf.placeholder` для установления входных данных графа\n",
        "* выполнение графа с `session.run`\n",
        "* ручная инициализация переменных\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "e582IjyF2eje"
      },
      "source": [
        "#### Перед конвертацией\n",
        "\n",
        "Здесь как могут выглядеть эти паттерны в коде использующем TensorFlow 1.x.\n",
        "\n",
        "```python\n",
        "in_a = tf.placeholder(dtype=tf.float32, shape=(2))\n",
        "in_b = tf.placeholder(dtype=tf.float32, shape=(2))\n",
        "\n",
        "def forward(x):\n",
        "  with tf.variable_scope(\"matmul\", reuse=tf.AUTO_REUSE):\n",
        "    W = tf.get_variable(\"W\", initializer=tf.ones(shape=(2,2)),\n",
        "                        regularizer=tf.contrib.layers.l2_regularizer(0.04))\n",
        "    b = tf.get_variable(\"b\", initializer=tf.zeros(shape=(2)))\n",
        "    return W * x + b\n",
        "\n",
        "out_a = forward(in_a)\n",
        "out_b = forward(in_b)\n",
        "\n",
        "reg_loss = tf.losses.get_regularization_loss(scope=\"matmul\")\n",
        "\n",
        "with tf.Session() as sess:\n",
        "  sess.run(tf.global_variables_initializer())\n",
        "  outs = sess.run([out_a, out_b, reg_loss],\n",
        "      \t        feed_dict={in_a: [1, 0], in_b: [0, 1]})\n",
        "\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "QARwz4Xd2lc2"
      },
      "source": [
        "#### После конвертации"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "x0AVzBFRBPcU"
      },
      "source": [
        "В сконвертированном коде:\n",
        "\n",
        "* Переменные являются локальными объектами Python.\n",
        "* Функция `forward` все еще определяет вычисления.\n",
        "* Вызов `sess.run` заменен вызовом `forward`\n",
        "* Опциональный декоратор `tf.function` может быть добавлен для производительности.\n",
        "* Регуляризации вычисляются вручную без ссылок на глобальные коллекции.\n",
        "* **Нет сессий и плейсхолдеров.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "lXEZoLMP2cWJ"
      },
      "outputs": [],
      "source": [
        "W = tf.Variable(tf.ones(shape=(2,2)), name=\"W\")\n",
        "b = tf.Variable(tf.zeros(shape=(2)), name=\"b\")\n",
        "\n",
        "@tf.function\n",
        "def forward(x):\n",
        "  return W * x + b\n",
        "\n",
        "out_a = forward([1,0])\n",
        "print(out_a)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YmE96A_1jZTg"
      },
      "outputs": [],
      "source": [
        "out_b = forward([0,1])\n",
        "\n",
        "regularizer = tf.keras.regularizers.l2(0.04)\n",
        "reg_loss = regularizer(W)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ycDxY9nL268-"
      },
      "source": [
        "### Модели основанные на `tf.layers`"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "K-bIk7wL48U7"
      },
      "source": [
        "Модуль `tf.layers` используется для содержания layer-функций использующих `tf.variable_scope` для определения и переиспользования переменных."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8I_qKpT73KyM"
      },
      "source": [
        "#### До конвертации\n",
        "```python\n",
        "def model(x, training, scope='model'):\n",
        "  with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):\n",
        "    x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu,\n",
        "          kernel_regularizer=tf.contrib.layers.l2_regularizer(0.04))\n",
        "    x = tf.layers.max_pooling2d(x, (2, 2), 1)\n",
        "    x = tf.layers.flatten(x)\n",
        "    x = tf.layers.dropout(x, 0.1, training=training)\n",
        "    x = tf.layers.dense(x, 64, activation=tf.nn.relu)\n",
        "    x = tf.layers.batch_normalization(x, training=training)\n",
        "    x = tf.layers.dense(x, 10, activation=tf.nn.softmax)\n",
        "    return x\n",
        "\n",
        "train_out = model(train_data, training=True)\n",
        "test_out = model(test_data, training=False)\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "b8_Ii7CQ3fK-"
      },
      "source": [
        "#### После конвертации"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "BsAseSMfB9XN"
      },
      "source": [
        "* Простой стек слоев аккуратно встраивается в `tf.keras.Sequential`. (Для более сложных моделей см. [пользовательские слои и модели](keras/custom_layers_and_models.ipynb), и [функциональный API](keras/functional.ipynb).)\n",
        "* Модель отслеживает переменные и потери регуляризации.\n",
        "* Преобразование взаимно-однозначно поскольку существует прямое отображение из `tf.layers` в `tf.keras.layers`.\n",
        "\n",
        "Большинство аргументов остались прежними. Но обратите внимание на различия:\n",
        "\n",
        "* Аргумент `training` передается моделью каждому слою при его запуске.\n",
        "* Первого аргумента исходной функции `model` (вводный `x`) больше нет. Это связано с тем, что слои объекта отделяют построение модели от вызова модели.\n",
        "\n",
        "\n",
        "Также заметьте что:\n",
        "\n",
        "* Если вы использовали регуляризаторы инициализаторов из  `tf.contrib`, у них больше изменений аргументов чем у остальных.\n",
        "* Код больше не записывает в коллекции, так что функции наподобие `tf.losses.get_regularization_loss` больше не возращают эти значения, что может нарушить ваши циклы обучения."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "DLAPORrN3lct"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.04),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10, activation='softmax')\n",
        "])\n",
        "\n",
        "train_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "test_data = tf.ones(shape=(1, 28, 28, 1))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "6nWh6IXvkMKv"
      },
      "outputs": [],
      "source": [
        "train_out = model(train_data, training=True)\n",
        "print(train_out)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YnAdIDLlj3go"
      },
      "outputs": [],
      "source": [
        "test_out = model(test_data, training=False)\n",
        "print(test_out)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "sAgqwCJBMx_x"
      },
      "outputs": [],
      "source": [
        "# Здесь все обучаемые переменные.\n",
        "len(model.trainable_variables)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "uX6knaYMNM8p"
      },
      "outputs": [],
      "source": [
        "# Здесь потери регуляризации.\n",
        "model.losses"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "9moqw5E_4Cwl"
      },
      "source": [
        "### Смесь переменных и tf.layers\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "80DEsImmq6VX"
      },
      "source": [
        "Существующий код часто смешивает низкоуровневые TF 1.x переменные и операции с высокоуровневыми `tf.layers`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "oZe9L6RR4OcP"
      },
      "source": [
        "#### До конвертации\n",
        "```python\n",
        "def model(x, training, scope='model'):\n",
        "  with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):\n",
        "    W = tf.get_variable(\n",
        "      \"W\", dtype=tf.float32,\n",
        "      initializer=tf.ones(shape=x.shape),\n",
        "      regularizer=tf.contrib.layers.l2_regularizer(0.04),\n",
        "      trainable=True)\n",
        "    if training:\n",
        "      x = x + W\n",
        "    else:\n",
        "      x = x + W * 0.5\n",
        "    x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu)\n",
        "    x = tf.layers.max_pooling2d(x, (2, 2), 1)\n",
        "    x = tf.layers.flatten(x)\n",
        "    return x\n",
        "\n",
        "train_out = model(train_data, training=True)\n",
        "test_out = model(test_data, training=False)\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "y6ORX7cD4TkD"
      },
      "source": [
        "#### После конвертации"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "2BaRwog5CBpz"
      },
      "source": [
        "Для конвертации этого кода следуйте паттерну отображения слоев в слои как и в предыдущем примере.\n",
        "\n",
        "`tf.variable_scope` фактически является слоем сам по себе. Поэтому перепишите его как `tf.keras.layers.Layer`. См. [руководство](keras/custom_layers_and_models.ipynb) для подробностей.\n",
        "\n",
        "В общем паттерн следующий:\n",
        "\n",
        "* Собрать параметры слоев в `__init__`.\n",
        "* Создать переменные в `build`.\n",
        "* Выполнить вычисления в `call` и вернуть результат.\n",
        "\n",
       "`tf.variable_scope` по сути является собственным слоем. Поэтому перепишите его как `tf.keras.layers.Layer`. Смотрите [руководство](keras/custom_layers_and_models.ipynb) для деталей."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YcCAjNuP4NVh"
      },
      "outputs": [],
      "source": [
        "# Создайте пользовательский слой для части модели\n",
        "class CustomLayer(tf.keras.layers.Layer):\n",
        "  def __init__(self, *args, **kwargs):\n",
        "    super(CustomLayer, self).__init__(*args, **kwargs)\n",
        "\n",
        "  def build(self, input_shape):\n",
        "    self.w = self.add_weight(\n",
        "        shape=input_shape[1:],\n",
        "        dtype=tf.float32,\n",
        "        initializer=tf.keras.initializers.ones(),\n",
        "        regularizer=tf.keras.regularizers.l2(0.02),\n",
        "        trainable=True)\n",
        "\n",
        "  # Метод call будет иногда использоваться в режиме графа,\n",
        "  # training превратится в тензор\n",
        "  @tf.function\n",
        "  def call(self, inputs, training=None):\n",
        "    if training:\n",
        "      return inputs + self.w\n",
        "    else:\n",
        "      return inputs + self.w * 0.5"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "dR_QO6_wBgMm"
      },
      "outputs": [],
      "source": [
        "custom_layer = CustomLayer()\n",
        "print(custom_layer([1]).numpy())\n",
        "print(custom_layer([1], training=True).numpy())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "VzqaIf4E42oY"
      },
      "outputs": [],
      "source": [
        "train_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "test_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "\n",
        "# Build the model including the custom layer\n",
        "model = tf.keras.Sequential([\n",
        "    CustomLayer(input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu'),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "])\n",
        "\n",
        "train_out = model(train_data, training=True)\n",
        "test_out = model(test_data, training=False)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "dS5ed_jjOkvh"
      },
      "source": [
        "Некоторые вещи на заметку:\n",
        "\n",
        "* Подклассы моделей и слоев Keras нужно запускать и в v1 графах (без автоматического контроля зависимостей) и в режиме eager mode\n",
        "  * Оберните `call()` в `tf.function()` чтобы получить autograph и автоматический контроль зависимостей\n",
        "\n",
        "* Не забудьте принять аргумент `training` в `call`.\n",
        "    * Иногда это `tf.Tensor`\n",
        "    * Иногда это булеан Python.\n",
        "\n",
        "* Создайте переменные модели в конструкторе или `def build()` используя `self.add_weight()`.\n",
        "  * В `build` у вас есть доступ к размерности входных данных, так что создайте веса с совпадающими размерностями.\n",
        "  * Использование `tf.keras.layers.Layer.add_weight` позволяет Keras отслеживать переменные и потери регуляризации.\n",
        "\n",
        "* Не храните `tf.Tensors` в своих объектах.\n",

        "  * Они могут быть созданы либо в `tf.function` либо в контексте eager, и эти тензоры ведут себя по-другому.\n",
        "  * Используйте `tf.Variable`s для состояния, их всегда можно использовать из обеих контекстов\n",
        "  * `tf.Tensors` это только промежуточные значения."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ulaB1ymO4pw5"
      },
      "source": [
        "### Замечание о Slim и contrib.layers\n",
        "\n",
        "Большое количество старого TensorFlow 1.x кода использует библиотеку [Slim](https://ai.googleblog.com/2016/08/tf-slim-high-level-library-to-define.html) которая входит в пакет TensorFlow 1.x в качестве `tf.contrib.layers`. В качестве модуля `contrib` она более не доступна в TensorFlow 2.0, даже в `tf.compat.v1`. Конвертация кода использовавшего Slim в TF 2.0 запутаннее чем конвертация репозиториев использующих `tf.layers`. Имеет смысл сперва сконвертировать ваш Slim код сперва в`tf.layers`, а затем конвертировать в Keras.\n",
        "\n",
        "* Уберите `arg_scopes`, все аргументы должны быть явными\n",
        "* Если вы используете их, поделите `normalizer_fn` и `activation_fn` каждый в свой собственный слой\n",
        "* Separable сверточные слои отображаются в один или более различных слоев Keras (по глубине, поточечно, и separable слои Keras)\n",
        "* Slim и `tf.layers` имеют разные имена аргументов и значения по умолчанию\n",
        "* Некоторые аргументы имеют разные размерности\n",
        "* Если вы используете предобученные модели Slim, попробуйте `tf.keras.applications` или [TFHub](https://tensorflow.orb/hub)\n",
        "\n",
        "Некоторые слои `tf.contrib` возможно не были перемещены в ядро TensorFlow, а вместо этого были перемещены в пакет [TF add-ons](https://github.com/tensorflow/addons).\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "1w72KrXm4yZR"
      },
      "source": [
        "## Обучение"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "56PQxTgy2bpI"
      },
      "source": [
        "Существует много способов подачи данных в модели `tf.keras`. Они допускают генераторы Python и массивы Numpy в качестве входных данных.\n",
        "\n",
        "Рекомендуемы способ подачи данных в модель это - использовать пакет `tf.data`, который содержит набор высокопроизводительных классов для манипуляций с данными.\n",
        "\n",
        "Если вы все еще используете `tf.queue`, они поддерживаются только как структуры данных, а не как входные конвейеры."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "m6htasZ7iBB4"
      },
      "source": [
        "### Использование наборов данных"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "loTPH2Pz4_Oj"
      },
      "source": [
        "Пакет [TensorFlow Datasets](https://tensorflow.org/datasets)  (`tfds`) содержит утилиты для загрузки предопределенных баз данных как объектов `tf.data.Dataset`.\n",
        "\n",
        "Например, загрузим MNISTdataset, используя `tfds`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "BMgxaLH74_s-"
      },
      "outputs": [],
      "source": [
        "datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)\n",
        "mnist_train, mnist_test = datasets['train'], datasets['test']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "hPJhEuvj5VfR"
      },
      "source": [
        "Затем приготовим данные для обучения:\n",
        "\n",
        "  * Изменим размер каждого изображения.\n",
        "  * Перемешаем порядок примеров.\n",
        "  * Соберем batches изображений и меток.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "StBRHtJM2S7o"
      },
      "outputs": [],
      "source": [
        "BUFFER_SIZE = 10 # Используйте намного большее значение для настоящего кода.\n",
        "BATCH_SIZE = 64\n",
        "NUM_EPOCHS = 5\n",
        "\n",
        "\n",
        "def scale(image, label):\n",
        "  image = tf.cast(image, tf.float32)\n",
        "  image /= 255\n",
        "\n",
        "  return image, label"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SKq14zKKFAdv"
      },
      "source": [
        " Чтобы пример оставался коротким обрежем данные, чтобы он возвращал только 5 batches:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "_J-o4YjG2mkM"
      },
      "outputs": [],
      "source": [
        "train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE).take(5)\n",
        "test_data = mnist_test.map(scale).batch(BATCH_SIZE).take(5)\n",
        "\n",
        "STEPS_PER_EPOCH = 5\n",
        "\n",
        "train_data = train_data.take(STEPS_PER_EPOCH)\n",
        "test_data = test_data.take(STEPS_PER_EPOCH)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "XEqdkH54VM6c"
      },
      "outputs": [],
      "source": [
        "image_batch, label_batch = next(iter(train_data))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mSev7vZC5GJB"
      },
      "source": [
        "### Использование обучающик циклов Keras\n",
        "\n",
        "Если вам не нужен низкоуровневый коноль процесса обучения модели, рекомендуется использовать встроенные в Keras методы `fit`, `evaluate` и `predict`. Эти методы обеспечивают единый интерфейс обучения модели независимо от реализации (sequential, functional или sub-classed).\n",
        "\n",
        "Преимущества этих методов включают:\n",
        "\n",
        "* Они допускают массивы Numpy, генераторы Python и `tf.data.Datasets`\n",
        "* Они применяют регуляризационные и активационные потери автоматически.\n",
        "* Они поддерживают `tf.distribute` [для обучения на нескольких устройствах](distributed_training.ipynb).\n",
        "* Они поддерживают произвольные вызываемые объекты как потери и метрики.\n",
        "* Они поддерживают коллбеки такие как `tf.keras.callbacks.TensorBoard` и пользовательские коллбеки.\n",
        "* Они производительны, автоматически используя графы TensorFlow.\n",
        "\n",
        "Приведем пример обучения модели с ипользованием `Dataset`. (Подробнее о том как это работает смотри [тьюториалы](../tutorials).)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "uzHFCzd45Rae"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.02),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10, activation='softmax')\n",
        "])\n",
        "\n",
        "# Model is the full model w/o custom layers\n",
        "model.compile(optimizer='adam',\n",
        "              loss='sparse_categorical_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "model.fit(train_data, epochs=NUM_EPOCHS)\n",
        "loss, acc = model.evaluate(test_data)\n",
        "\n",
        "print(\"Loss {}, Accuracy {}\".format(loss, acc))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "akpeOb09YBhq"
      },
      "source": [
        "### Напишите свой собственный цикл\n",
        "\n",
        "Если обучающий шаг модели Keras подходит вам, но вне шага вам нужет больший контроль, рассмотрите использование `tf.keras.model.train_on_batch` method,  в вашем собтвенном цикле итерации данных.\n",
        "\n",
        "Запомните: Многие вещи могут быть реализованы как `tf.keras.Callback`.\n",
        "\n",
        "Этот метод имеет много преимуществ перед методами, упомянутыми в предыдущем разделе, но он дает пользователю контроль над внешним циклом.\n",
        "\n",
        "Вы также можете использовать `tf.keras.model.test_on_batch` или `tf.keras.Model.evaluate` чтобы проверить производительность во время обучения.\n",
        "\n",
        "Примечание: `train_on_batch` и `test_on_batch` по умолчанию возвращают потерю и метрики для одного batch. Если вы передаете `reset_metrics=False` они возвращают накопленные метрики и вы должны помнить своевременно сбрасывать накопители метрик. Таже помните, что некоторые метрики, такие как `AUC` требуют `reset_metrics=False` для корректного вычисления.\n",
        "\n",
        "Чтобы продолжить обучение вышеуказанной модели:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "eXr4CyJMtJJ6"
      },
      "outputs": [],
      "source": [
        "# Model это полная модель без пользовательских слоев\n",
        "model.compile(optimizer='adam',\n",
        "              loss='sparse_categorical_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "metrics_names = model.metrics_names\n",
        "\n",
        "for epoch in range(NUM_EPOCHS):\n",
        "  #Reset the metric accumulators\n",
        "  model.reset_metrics()\n",
        "\n",
        "  for image_batch, label_batch in train_data:\n",
        "    result = model.train_on_batch(image_batch, label_batch)\n",
        "    print(\"train: \",\n",
        "          \"{}: {:.3f}\".format(metrics_names[0], result[0]),\n",
        "          \"{}: {:.3f}\".format(metrics_names[1], result[1]))\n",
        "  for image_batch, label_batch in test_data:\n",
        "    result = model.test_on_batch(image_batch, label_batch,\n",
        "                                 # return accumulated metrics\n",
        "                                 reset_metrics=False)\n",
        "  print(\"\\neval: \",\n",
        "        \"{}: {:.3f}\".format(metrics_names[0], result[0]),\n",
        "        \"{}: {:.3f}\".format(metrics_names[1], result[1]))\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "LQTaHTuK5S5A"
      },
      "source": [
        "<p id=\"custom_loops\"/>\n",
        "\n",
        "### Настройте шаг обучения\n",
        "\n",
        "Если вам нужны большая гибкость и контроль, вы можете получить их реализовав собственный цикл обучения. Есть три шага:\n",
        "\n",
        "1. Проитерируйте генератор Python или `tf.data.Dataset` чтобы получить пакеты примеров.\n",
        "2. Используйте `tf.GradientTape` чтобы собрать градиенты.\n",
        "3. Используйте `tf.keras.optimizer` чтобы применить обновления весов к переменным модели.\n",
        "\n",
        "Помните:\n",
        "\n",
        "* Всегда включайте аргумент `training` в метод `call` подклассов слоев и моделей.\n",
        "* Убедитесь что вызываете модель с корректно установленным аргументом `training`.\n",
        "* В зависимости от использования, переменные модели могут не существовать, пока модель не будет запущена на пакете данных.\n",
        "* Вам нужно вручную обрабатывать такие вещи, как потери регуляризации для модели.\n",
        "\n",
        "Обратите внимание на упрощения относительно v1:\n",
        "\n",
        "* Нет необходимости запускать инициализаторы переменных. Переменные инициализируются при создании.\n",
        "* Нет необходимости добавлять зависимости ручного управления. Даже в операциях `tf.function` действующих как в eager mode."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "gQooejfYlQeF"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.02),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10, activation='softmax')\n",
        "])\n",
        "\n",
        "optimizer = tf.keras.optimizers.Adam(0.001)\n",
        "loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()\n",
        "\n",
        "@tf.function\n",
        "def train_step(inputs, labels):\n",
        "  with tf.GradientTape() as tape:\n",
        "    predictions = model(inputs, training=True)\n",
        "    regularization_loss = tf.math.add_n(model.losses)\n",
        "    pred_loss = loss_fn(labels, predictions)\n",
        "    total_loss = pred_loss + regularization_loss\n",
        "\n",
        "  gradients = tape.gradient(total_loss, model.trainable_variables)\n",
        "  optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n",
        "\n",
        "for epoch in range(NUM_EPOCHS):\n",
        "  for inputs, labels in train_data:\n",
        "    train_step(inputs, labels)\n",
        "  print(\"Finished epoch\", epoch)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kS7WW5Z75ve3"
      },
      "source": [
        "### Метрики в новом стиле\n",
        "\n",
        "В TensorFlow 2.0, метрики являются объектами. Метрики работают и eagerly и в `tf.function`. Объекты-метрики обладают следующими методами:\n",
        "\n",
        "* `update_state()` — добавить новые наблюдения\n",
        "* `result()` — получить текущий результат метрики при данных наблюдаемых значениях\n",
        "* `reset_states()` — очистить все наблюдения.\n",
        "\n",
        "Объект сам является вызываемым. Вызов обновляет состояние новыми наблюдениями, как и с `update_state`, и возвращает новый результат метрики\n",
        "\n",
        "Вам не нужно вручную инициализировать переменные метрики, и, поскольку у TensorFlow 2.0 автоматическое управление зависимостями, вам не нужно беспокоиться и об этом.\n",
        "\n",
        "В приведенном ниже коде используется метрика для отслеживания среднего значения потерь, наблюдаемых в пользовательском цикле обучения."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "HAbA0fKW58CH"
      },
      "outputs": [],
      "source": [
        "# Создайте метрики\n",
        "loss_metric = tf.keras.metrics.Mean(name='train_loss')\n",
        "accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')\n",
        "\n",
        "@tf.function\n",
        "def train_step(inputs, labels):\n",
        "  with tf.GradientTape() as tape:\n",
        "    predictions = model(inputs, training=True)\n",
        "    regularization_loss = tf.math.add_n(model.losses)\n",
        "    pred_loss = loss_fn(labels, predictions)\n",
        "    total_loss = pred_loss + regularization_loss\n",
        "\n",
        "  gradients = tape.gradient(total_loss, model.trainable_variables)\n",
        "  optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n",
        "  # Обновите метрики\n",
        "  loss_metric.update_state(total_loss)\n",
        "  accuracy_metric.update_state(labels, predictions)\n",
        "\n",
        "\n",
        "for epoch in range(NUM_EPOCHS):\n",
        "  # Сбросьте метрики\n",
        "  loss_metric.reset_states()\n",
        "  accuracy_metric.reset_states()\n",
        "\n",
        "  for inputs, labels in train_data:\n",
        "    train_step(inputs, labels)\n",
        "  # Получите результаты метрики\n",
        "  mean_loss = loss_metric.result()\n",
        "  mean_accuracy = accuracy_metric.result()\n",
        "\n",
        "  print('Epoch: ', epoch)\n",
        "  print('  loss:     {:.3f}'.format(mean_loss))\n",
        "  print('  accuracy: {:.3f}'.format(mean_accuracy))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JmMLBKs66DeA"
      },
      "source": [
        "## Сохранение и загрузка\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "5_QKn3Kl6TUu"
      },
      "source": [
        "### Совместимость контрольных точек\n",
        "\n",
        "TensorFlow 2.0 использует [контрольные точки основанные на объектах](checkpoint.ipynb).\n",
        "\n",
        "Контрольные точки в старом стиле основанные на именах по-прежнему могут быть загружены, если вы осторожны с ними.\n",
        "В процессе конвертации кода могут измениться имена переменных, но есть обходные пути.\n",
        "\n",
        "Самый простой подход - согласовать имена новой модели с именами в контрольной точке.:\n",
        "\n",
        "* У переменных все еще есть аргумент `name` который вы можете установить.\n",
        "* Модели Keras также используют аргумент `name`, который они устанавливают в качестве префикса для своих переменных.\n",
        "* Функция `tf.name_scope` может использоваться для установки префиксов имен переменных. Это сильно отличается от `tf.variable_scope`. Он влияет только на имена и не отслеживает переменные и их переиспользование.\n",
        "\n",
        "Если это не работает для вашего случая, попробуйте функцию `tf.compat.v1.train.init_from_checkpoint`. Она принимает аргумент `assignment_map`, который определяет соответствие старых и новых имен.\n",
        "\n",
        "Примечание: В отличие от основанных на объектах контрольных точек, которые могут [отложить загрузку] (checkpoint.ipynb#loading_mechanics), основанные на именах контрольных точек требуют, чтобы при вызове функции были созданы все переменные. Некоторые модели откладывают создание переменных до тех пор, пока вы не вызовете `build` или не запустите модель на пакете данных."
         ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "_ONjobDD6Uur"
      },
      "source": [
        "### Совместимость сохраненных моделей\n",
        "\n",
        "У совместимости для сохраненных моделей нет существенных проблем.\n",
        "\n",
        "* TensorFlow 1.x saved_models работают TensorFlow 2.0.\n",
        "* TensorFlow 2.0 saved_models даже загруженные работают в TensorFlow 1.x если все операции поддерживаются."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ewl9P3oZ6ZtR"
      },
      "source": [
        "## Estimators"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "YprVP9g3l6eG"
      },
      "source": [
        "### Обучение с оценщиками\n",
        "\n",
        "Оценщики поддерживаются TensorFlow 2.0.\n",
        "\n",
        "Когда вы используете оценщики, вы можете использовать `input_fn()`, `tf.estimator.TrainSpec`, и `tf.estimator.EvalSpec` из TensorFlow 1.x.\n",
        "\n",
        "Здесь пример использующий `input_fn` с train and evaluate specs."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "N5kZeJsF8lS2"
      },
      "source": [
        "#### Создание input_fn и train/eval specs"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "AOlXGO4J6jDh"
      },
      "outputs": [],
      "source": [
        "# Определим input_fn оценщика \n",
        "def input_fn():\n",
        "  datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)\n",
        "  mnist_train, mnist_test = datasets['train'], datasets['test']\n",
        "\n",
        "  BUFFER_SIZE = 10000\n",
        "  BATCH_SIZE = 64\n",
        "\n",
        "  def scale(image, label):\n",
        "    image = tf.cast(image, tf.float32)\n",
        "    image /= 255\n",
        "\n",
        "    return image, label[..., tf.newaxis]\n",
        "\n",
        "  train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)\n",
        "  return train_data.repeat()\n",
        "\n",
        "# Define train \u0026 eval specs\n",
        "train_spec = tf.estimator.TrainSpec(input_fn=input_fn,\n",
        "                                    max_steps=STEPS_PER_EPOCH * NUM_EPOCHS)\n",
        "eval_spec = tf.estimator.EvalSpec(input_fn=input_fn,\n",
        "                                  steps=STEPS_PER_EPOCH)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "_o6J48Nj9H5c"
      },
      "source": [
        "### Использование определения модели Keras"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "IXCQdhGq9SbB"
      },
      "source": [
        "Есть некоторые отличия в том, как построить ваши оценщики в TensorFlow 2.0.\n",
        "\n",
        "Мы рекомендуем вам определить модель используя Keras, потом используйте утилиту `tf.keras.model_to_estimator` для преобразования вашей модели в оценщика. Нижеприведенный код показывает как использовать эту утилиту когда создаешь и обучаешь оценщик."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "aelsClm3Cq4I"
      },
      "outputs": [],
      "source": [
        "def make_model():\n",
        "  return tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.02),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10, activation='softmax')\n",
        "  ])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "HJb6f8dtl6rr"
      },
      "outputs": [],
      "source": [
        "model = make_model()\n",
        "\n",
        "model.compile(optimizer='adam',\n",
        "              loss='sparse_categorical_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "estimator = tf.keras.estimator.model_to_estimator(\n",
        "  keras_model = model\n",
        ")\n",
        "\n",
        "tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "-ptTxL1q6flL"
      },
      "source": [
        "### Использование пользовательской `model_fn`\n",
        "\n",
        "Если у вас есть существующий пользовательский оценщик `model_fn`, который вам нужно поддерживать, вы можете конвертировать свой` model_fn` чтобы использовать модель Keras.\n",
        "\n",
        "Однако по соображениям совместимости пользовательский `model_fn` будет по-прежнему работать в стиле 1.x графа. Это означает, что нет будет eager execution и нет автоматического управления зависимостей.\n",
        "\n",
        "Использование моделей Keras в пользовательском `model_fn` аналогично использованию в пользовательском цикле обучения:\n",
        "\n",
        "* Установите фазу `training` соответствующе, основываясь на аргументе `mode`.\n",
        "* Явно передайте `trainable_variables` модели оптимизатору.\n",
        "\n",
        "Но есть важные различия отлосящиеся к [пользовательскому циклу](#custom_loop):\n",
        "\n",
        "* Вместо использования `model.losses` извлеките потери, используя` tf.keras.Model.get_losses_for`.\n",
        "* Извлеките обновления модели используя `tf.keras.Model.get_updates_for`\n",
        "\n",
        "Примечание: \"Updates\" это изменения которые необходимо применить к модели после каждого пакета. Например, скользящие средние среднего и дисперсии в слое `tf.keras.layers.BatchNormalization`.\n",
        "\n",
        "Следующий код создает оценщик из пользовательского `model_fn`, иллюстрируя все эти проблемы."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "iY16eZKW606-"
      },
      "outputs": [],
      "source": [
        "def my_model_fn(features, labels, mode):\n",
        "  model = make_model()\n",
        "\n",
        "  optimizer = tf.compat.v1.train.AdamOptimizer()\n",
        "  loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()\n",
        "\n",
        "  training = (mode == tf.estimator.ModeKeys.TRAIN)\n",
        "  predictions = model(features, training=training)\n",
        "\n",
        "  reg_losses = model.get_losses_for(None) + model.get_losses_for(features)\n",
        "  total_loss = loss_fn(labels, predictions) + tf.math.add_n(reg_losses)\n",
        "\n",
        "  accuracy = tf.compat.v1.metrics.accuracy(labels=labels,\n",
        "                                           predictions=tf.math.argmax(predictions, axis=1),\n",
        "                                           name='acc_op')\n",
        "\n",
        "  update_ops = model.get_updates_for(None) + model.get_updates_for(features)\n",
        "  minimize_op = optimizer.minimize(\n",
        "      total_loss,\n",
        "      var_list=model.trainable_variables,\n",
        "      global_step=tf.compat.v1.train.get_or_create_global_step())\n",
        "  train_op = tf.group(minimize_op, update_ops)\n",
        "\n",
        "  return tf.estimator.EstimatorSpec(\n",
        "    mode=mode,\n",
        "    predictions=predictions,\n",
        "    loss=total_loss,\n",
        "    train_op=train_op, eval_metric_ops={'accuracy': accuracy})\n",
        "\n",
        "# Создайте оценщик и обучите\n",
        "estimator = tf.estimator.Estimator(model_fn=my_model_fn)\n",
        "tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "g1l6VnOTodfA"
      },
      "source": [
        "### Готовые оценщики\n",
        "\n",
        "[Готовые оценщики](https://www.tensorflow.org/guide/premade_estimators) из семейств `tf.estimator.DNN*`, `tf.estimator.Linear*` и `tf.estimator.DNNLinearCombined*` все еще поддерживаются в TensorFlow 2.0 API, однако, некоторые аргументы изменились:\n",
        "\n",
        "1. `input_layer_partitioner`: Убрано в 2.0.\n",
        "2. `loss_reduction`: Обновлено до `tf.keras.losses.Reduction` вместо `tf.compat.v1.losses.Reduction`. Значение по умолчанию также изменилось и стало `tf.keras.losses.Reduction.SUM_OVER_BATCH_SIZE` вместо `tf.compat.v1.losses.Reduction.SUM`.\n",
        "3. `optimizer`, `dnn_optimizer` и `linear_optimizer`: эти аргументы обновились до `tf.keras.optimizers` вместо `tf.compat.v1.train.Optimizer`. \n",
        "\n",
        "Для переноса вышеуказанных изменений:\n",
        "1. Для `input_layer_partitioner` миграция не требуется поскольку [`Стратегия распределения`](https://www.tensorflow.org/guide/distributed_training) обработает это автоматически в TF 2.0.\n",
        "2. Для `loss_reduction`, проверьте [`tf.keras.losses.Reduction`](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/losses/Reduction) для поддерживаемых опций.\n",
        "3. Для аргументов `optimizer` args, если вы не передаете аргумента `optimizer`, `dnn_optimizer` или `linear_optimizer`, или если вы укажете в своем коде аргумент `optimizer` как `string`, вам не нужно ничего менять. `tf.keras.optimizers` используются по умолчанию. Иначе, вам нужно обновить его от `tf.compat.v1.train.Optimizer` до соответсвующей [`tf.keras.optimizers`](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/optimizers)\n",
        "\n",
        "#### Конвертер контрольных точек\n",
        "Миграция `optimizer` повредит контрольные точки в TF 1.x, так как` tf.keras.optimizer` генерирует другой набор переменных для сохранения в контрольных точках. Чтобы сделать контрольную пригодной к использованию после перехода на TF 2.0, пожалуйста, посмотрите инструмент конвертации контрольных точек для оптимизаторов, чтобы преобразовать контрольные точки из TF 1.x в TF 2.0. Преобразованные контрольные точки можно использовать для восстановления предварительно обученных моделей в TF 2.0."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "dt8ct9XCFqls"
      },
      "source": [
        "## TensorShape\n",
        "\n",
        "Этот класс был упрощен для хранения `int` вместо объектов `tf.compat.v1.Dimension`. Так что нет необходимости в вызове `.value()` чтобы получить `int`.\n",
        "\n",
        "Отдельные объекты `tf.compat.v1.Dimension` по-прежнему доступны из `tf.TensorShape.dims`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "x36cWcmM8Eu1"
      },
      "source": [
        "\n",
        "\n",
        "Следующее демонстрирует отличия TensorFlow 1.x и TensorFlow 2.0."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "PbpD-kHOZR4A"
      },
      "outputs": [],
      "source": [
        "# Создайте shape и выберите index\n",
        "i = 0\n",
        "shape = tf.TensorShape([16, None, 256])\n",
        "shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kDFck03neNy0"
      },
      "source": [
        "Если у вас есть это в TF 1.x:\n",
        "\n",
        "```python\n",
        "value = shape[i].value\n",
        "```\n",
        "\n",
        "Сделайте это в TF 2.0:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "KuR73QGEeNdH"
      },
      "outputs": [],
      "source": [
        "value = shape[i]\n",
        "value"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "bPWPNKRiZmkd"
      },
      "source": [
        "Если у вас есть это в TF 1.x:\n",
        "\n",
        "```python\n",
        "for dim in shape:\n",
        "    value = dim.value\n",
        "    print(value)\n",
        "```\n",
        "\n",
        "TСделайте это в TF 2.0:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "y6s0vuuprJfc"
      },
      "outputs": [],
      "source": [
        "for value in shape:\n",
        "  print(value)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "YpRgngu3Zw-A"
      },
      "source": [
        "Если у вас есть это в 1.x (Или используется любой другой метод размерности):\n",
        "\n",
        "```python\n",
        "dim = shape[i]\n",
        "dim.assert_is_compatible_with(other_dim)\n",
        "```\n",
        "\n",
        "Сделайте это в TF 2.0:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "LpViGEcUZDGX"
      },
      "outputs": [],
      "source": [
        "other_dim = 16\n",
        "Dimension = tf.compat.v1.Dimension\n",
        "\n",
        "if shape.rank is None:\n",
        "  dim = Dimension(None)\n",
        "else:\n",
        "  dim = shape.dims[i]\n",
        "dim.is_compatible_with(other_dim) # или любой другой метод размерности"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "GaiGe36dOdZ_"
      },
      "outputs": [],
      "source": [
        "shape = tf.TensorShape(None)\n",
        "\n",
        "if shape:\n",
        "  dim = shape.dims[i]\n",
        "  dim.is_compatible_with(other_dim) # или любой другой метод размерности"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "3kLLY0I3PI-l"
      },
      "source": [
        "Булево значение `tf.TensorShape` является `True` если ранг известен, `False` в противном случае."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "-Ow1ndKpOnJd"
      },
      "outputs": [],
      "source": [
        "print(bool(tf.TensorShape([])))      # Скаляр\n",
        "print(bool(tf.TensorShape([0])))     # Вектор длины 0\n",
        "print(bool(tf.TensorShape([1])))     # Вектор длины 1\n",
        "print(bool(tf.TensorShape([None])))  # Вектор неизвестной длины\n",
        "print(bool(tf.TensorShape([1, 10, 100])))       # 3D тензор\n",
        "print(bool(tf.TensorShape([None, None, None]))) # 3D тензор с неизвестными размерностями\n",
        "print()\n",
        "print(bool(tf.TensorShape(None)))  # Тензор неизвестного ранга."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "lwswSCLT9g63"
      },
      "source": [
        "## Другие поведенческие изменения\n",
        "\n",
        "В TensorFlow 2.0 есть несколько других поведенческих изменений, с которыми вы можете столкнуться.\n",
        "\n",
        "\n",
        "### ResourceVariables\n",
        "\n",
        "TensorFlow 2.0 создает по умолчанию `ResourceVariables`, а не `RefVariables`.\n",
        "\n",
        "`ResourceVariables` закрыты для записи, и обеспечивают лучшие гарантии согласовенности.\n",
        "\n",
        "* Это может изменить поведение в граничных случаях.\n",
        "* Это может иногда создавать дополнительные копии и использовать большие объемы памяти\n",
        "* Это можно отключить, передав `use_resource = False` конструктору` tf.Variable`.\n",
        "\n",
        "### Control Flow\n",
        "\n",
        "Реализация control flow была упрощена, поэтому в TensorFlow 2.0 создаются другие графы."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vKX6AdTAQhB-"
      },
      "source": [
        "## Выводы\n",
        "\n",
        "Общий процесс следующий:\n",
        "\n",
        "1. Запуститсе upgrade script.\n",
        "2. Удалите символы contrib.\n",
        "3. Переключите ваши модели в объектно ориентированный стиль (Keras).\n",
        "4. Используйте циклы обучения и оценки `tf.keras` или `tf.estimator` там где вы можете.\n",
        "5. Иначе используйте пользовательские циклы, но избегайте сессий и коллекций.\n",
        "\n",
        "\n",
        "Для преобразования кода в идиоматический TensorFlow 2.0 требуется небольшая работа, но каждое изменение приводит к:\n",
        "\n",
        "* Меньшему количеству строк кода.\n",
        "* Увеличившейся понятности и простоте.\n",
        "* К более легкой отладке.\n",
        "\n"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "migrate.ipynb",
      "private_outputs": true,
      "provenance": [],
      "toc_visible": true,
      "version": "0.3.2"
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
